//! Create documentation pages for each rule. Pages are printed as Markdown and
//! get added to the website.

use std::{
    fmt::{self, Write},
    path::PathBuf,
};

use oxc_linter::table::RuleTableRow;

use super::HtmlWriter;

pub fn render_rule_docs_page(rule: &RuleTableRow) -> Result<String, fmt::Error> {
    const APPROX_FIX_CATEGORY_AND_PLUGIN_LEN: usize = 512;
    let RuleTableRow { name, documentation, plugin, turned_on_by_default, autofix, category } =
        rule;

    let mut page = HtmlWriter::with_capacity(
        documentation.map_or(0, str::len) + name.len() + APPROX_FIX_CATEGORY_AND_PLUGIN_LEN,
    );

    writeln!(
        page,
        "<!-- This file is auto-generated by {}. Do not edit it manually. -->\n",
        file!()
    )?;
    writeln!(page, r#"# {plugin}/{name} <Badge type="info" text="{category}" />"#)?;

    // rule metadata
    page.div(r#"class="rule-meta""#, |p| {
        if *turned_on_by_default {
            p.Alert(r#"class="default-on" type="success""#, |p| {
                p.writeln(r#"<span class="emoji">✅</span> This rule is turned on by default."#)
            })?;
        }

        if let Some(emoji) = autofix.emoji() {
            p.Alert(r#"class="fix" type="info""#, |p| {
                p.writeln(format!(
                    r#"<span class="emoji">{}</span> {}"#,
                    emoji,
                    autofix.description()
                ))
            })?;
        }

        Ok(())
    })?;

    // rule documentation
    if let Some(docs) = documentation {
        writeln!(page, "\n{}", *docs)?;
    }

    let rule_source = rule_source(rule);
    writeln!(page, "\n## References")?;
    writeln!(page, "- [Rule Source]({rule_source})")?;

    Ok(page.into())
}

fn rule_source(rule: &RuleTableRow) -> String {
    use std::sync::OnceLock;

    use project_root::get_project_root;

    const GITHUB_URL: &str = "https://github.com/oxc-project/oxc/blob/main";
    const LINT_RULES_DIR: &str = "crates/oxc_linter/src/rules";
    static ROOT: OnceLock<PathBuf> = OnceLock::new();

    let root = ROOT.get_or_init(|| get_project_root().unwrap());

    // Some rules are folders with a mod.rs file, others are just a rust file
    let mut rule_path =
        root.join(LINT_RULES_DIR).join(&rule.plugin).join(rule.name.replace('-', "_"));
    if rule_path.is_dir() {
        rule_path.push("mod.rs");
    } else {
        rule_path.set_extension("rs");
    }

    assert!(rule_path.exists(), "Rule source not found: {}", rule_path.display());
    assert!(rule_path.is_file(), "Rule source is not a file: {}", rule_path.display());

    rule_path.to_string_lossy().replace(root.to_str().unwrap(), GITHUB_URL)
}
